package com.cims.dao.hibernate;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

/**
 * Hibernate Utility class with a convenient method to get Session Factory object.
 * 
 * @author binhpv
 */
public class HibernateUtil{

	private static final SessionFactory	sessionFactory;

	static{
		try{
			// Create the SessionFactory from standard (hibernate.cfg.xml) config file.
			sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
		}catch(Throwable ex){
			// Log the exception.
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static SessionFactory getSessionFactory(){
		return sessionFactory;
	}

	@SuppressWarnings("unchecked")
	public static <T>T findByID(Class<T> className, Serializable id){
		T vo = null;
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		try{
			session = factory.openSession();

			vo = (T)session.get(className, id);
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}

		return vo;
	}

	@SuppressWarnings("unchecked")
	public static <T>List<T> selectAll(Class<T> cl){
		List<T> lstVo = null;
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;

		try{
			session = factory.openSession();

			lstVo = session.createCriteria(cl).list();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}

		return lstVo;
	}

	@SuppressWarnings("unchecked")
	public static <T>List<T> selectAll(Class<T> cl, String order){
		List<T> lstVo = null;
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;

		try{
			session = factory.openSession();
			Criteria crit = session.createCriteria(cl);
			crit.addOrder(Order.asc(order));
			lstVo = crit.list();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}

		return lstVo;
	}

	@SuppressWarnings("unchecked")
	public static <T>List<T> selectAll(Class<T> cl, String[] arrOrder){
		List<T> lstVo = null;
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;

		try{
			session = factory.openSession();
			Criteria crit = session.createCriteria(cl);
			for(String order : arrOrder){
				crit.addOrder(Order.asc(order));
			}
			lstVo = crit.list();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}

		return lstVo;
	}

	public static <T>boolean insertVo(T vo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			session.save(vo);
			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>boolean insertLstVo(List<T> lstVo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			for(T vo : lstVo){
				session.save(vo);
			}

			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>boolean updateVo(T vo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			session.update(vo);
			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>boolean updateLstVo(List<T> lstVo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			for(T vo : lstVo){
				session.update(vo);
			}

			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>boolean saveOrUpdate(T vo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			session.saveOrUpdate(vo);
			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>boolean deleteVo(T vo){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		Transaction trans = null;
		try{
			session = factory.openSession();
			trans = session.beginTransaction();

			session.delete(vo);
			trans.commit();
			trans = null;
			return true;
		}catch(Exception ex){
			ex.printStackTrace();
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			return false;
		}finally{
			if(trans != null){
				trans.rollback();
				trans = null;
			}
			if(session != null && session.isOpen()){
				session.close();
			}
		}
	}

	public static <T>Integer countRecords(Class<T> cl){
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		try{
			session = factory.openSession();

			return (Integer)session.createCriteria(cl).setProjection(Projections.rowCount()).uniqueResult();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}

		return null;
	}

	/**
	 * <strong>findOne</strong><br>
	 * <br>
	 * Find entity object by query
	 * 
	 * @param cl
	 * @param query
	 * @return
	 */
	public static <E>E findOne(Class<E> e, String queryStr){

		E vo = null;
		SessionFactory factory = HibernateUtil.getSessionFactory();
		Session session = null;
		try{
			session = factory.openSession();
			Query query = session.createQuery(queryStr);
			List<E> list = query.list();
			if(list.size() > 0){
				return list.get(0);
			}
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			if(session != null && session.isOpen()){
				session.close();
			}
		}
		return vo;
	}
}